#include "ibms_in.h"

static sig_atomic_t		g_SIGTERM_flag = 0 ;
static sig_atomic_t		g_SIGUSR1_flag = 0 ;
static sig_atomic_t		g_SIGUSR2_flag = 0 ;

static void sig_set_flag( int sig_no )
{
	if( sig_no == SIGTERM )
	{
		g_SIGTERM_flag = 1 ;
	}
	else if( sig_no == SIGUSR1 )
	{
		g_SIGUSR1_flag = 1 ;
	}
	else if( sig_no == SIGUSR2 )
	{
		g_SIGUSR2_flag = 1 ;
	}
	
	return;
}

static int monitor( struct IbmsEnv *p_env )
{
	struct sigaction	act ;
	
	pid_t			pid ;
	int			status ;
	
	int			nret = 0 ;
	
	p_env->listen_session.netaddr.sock = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
	if( p_env->listen_session.netaddr.sock == -1 )
	{
		ERRORLOGSG( "socket failed , errno[%d]" , errno );
		return -1;
	}
	else
	{
		INFOLOGSG( "socket ok[%d]" , p_env->listen_session.netaddr.sock );
	}
	
	SetHttpNonblock( p_env->listen_session.netaddr.sock );
	SetHttpReuseAddr( p_env->listen_session.netaddr.sock );
	SetHttpNodelay( p_env->listen_session.netaddr.sock , 1 );
	
	strncpy( p_env->listen_session.netaddr.ip , p_env->ibms_conf.ibms.server.ip , sizeof(p_env->listen_session.netaddr.ip)-1 );
	p_env->listen_session.netaddr.port = p_env->ibms_conf.ibms.server.port ;
	SETNETADDRESS( p_env->listen_session.netaddr )
	nret = bind( p_env->listen_session.netaddr.sock , (struct sockaddr *) & (p_env->listen_session.netaddr.addr) , sizeof(struct sockaddr) ) ;
	if( nret == -1 )
	{
		ERRORLOGSG( "bind[%s:%d][%d] failed , errno[%d]" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock , errno );
		close( p_env->listen_session.netaddr.sock );
		return -1;
	}
	else
	{
		INFOLOGSG( "bind[%s:%d][%d] ok" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock );
	}
	
	nret = listen( p_env->listen_session.netaddr.sock , 10240 ) ;
	if( nret == -1 )
	{
		ERRORLOGSG( "listen[%s:%d][%d] failed , errno[%d]" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock , errno );
		close( p_env->listen_session.netaddr.sock );
		return -1;
	}
	else
	{
		INFOLOGSG( "listen[%s:%d][%d] ok" , p_env->listen_session.netaddr.ip , p_env->listen_session.netaddr.port , p_env->listen_session.netaddr.sock );
	}
	
	signal( SIGCLD , SIG_DFL );
	signal( SIGCHLD , SIG_DFL );
	signal( SIGPIPE , SIG_IGN );
	act.sa_handler = & sig_set_flag ;
	sigemptyset( & (act.sa_mask) );
	act.sa_flags = 0 ;
	sigaction( SIGTERM , & act , NULL );
	act.sa_flags = SA_RESTART ;
	signal( SIGCLD , SIG_DFL );
	sigaction( SIGUSR1 , & act , NULL );
	sigaction( SIGUSR2 , & act , NULL );
	
	while(1)
	{
		nret = pipe( p_env->pipe_session.pipe_fds ) ;
		if( nret == -1 )
		{
			ERRORLOGSG( "pipe failed , errno[%d]" , errno );
			return -1;
		}
		else
		{
			DEBUGLOGSG( "pipe ok[%d][%d]" , p_env->pipe_session.pipe_fds[0] , p_env->pipe_session.pipe_fds[1] );
		}
		
		pid = fork() ;
		if( pid == -1 )
		{
			ERRORLOGSG( "fork failed , errno[%d]" , errno );
			return -1;
		}
		else if( pid == 0 )
		{
			INFOLOGSG( "child : [%ld] fork [%ld]" , getppid() , getpid() );
			close( p_env->pipe_session.pipe_fds[1] );
			return -worker( p_env );
		}
		else
		{
			INFOLOGSG( "parent : [%ld] fork [%ld]" , getpid() , pid );
			close( p_env->pipe_session.pipe_fds[0] );
			SetHttpNonblock( p_env->pipe_session.pipe_fds[1] );
		}
		
_GOTO_WAITPID :
		
		pid = waitpid( pid , & status , 0 );
		if( pid == -1 )
		{
			if( g_SIGTERM_flag )
			{
				break;
			}
			else if( g_SIGUSR1_flag )
			{
				char		ch = 'L' ;
				
				char		*file_content = NULL ;
				int		file_len ;
				ibms_conf	ibms_conf ;
				
				g_SIGUSR1_flag = 0 ;
				
				nret = (int)write( p_env->pipe_session.pipe_fds[1] , & ch , 1 );
				if( nret == -1 )
				{
					ERRORLOGSG( "write pipe failed , errno[%d]" , errno );
					return -1;
				}
				else
				{
					INFOLOGSG( "write pipe ok" );
				}
				
				file_content = StrdupEntireFile( p_env->ibms_conf_pathfilename , & file_len ) ;
				if( file_content == NULL )
				{
					ERRORLOGSG( "StrdupEntireFile[%s] failed" , p_env->ibms_conf_pathfilename );
					goto _GOTO_WAITPID;
				}
				
				memset( & ibms_conf , 0x00 , sizeof(ibms_conf) );
				nret = DSCDESERIALIZE_JSON_ibms_conf( "GB18030" , file_content , & file_len , & ibms_conf ) ;
				free( file_content );
				if( nret )
				{
					ERRORLOGSG( "DSCDESERIALIZE_JSON_ibms_conf[%s] failed[%d]" , p_env->ibms_conf_pathfilename , nret );
					goto _GOTO_WAITPID;
				}
				
				strcpy( p_env->ibms_conf.ibms.log.iblog_server , ibms_conf.ibms.log.iblog_server );
				strcpy( p_env->ibms_conf.ibms.log.event_output , ibms_conf.ibms.log.event_output );
				strcpy( p_env->ibms_conf.ibms.log.monitor_loglevel , ibms_conf.ibms.log.monitor_loglevel );
				strcpy( p_env->ibms_conf.ibms.log.monitor_output , ibms_conf.ibms.log.monitor_output );
				
				INFOLOGSG( "InitLogEnv iblog_server[%s] event_output[%s] monitor_output[%s][%s]" , p_env->ibms_conf.ibms.log.iblog_server , p_env->ibms_conf.ibms.log.event_output , p_env->ibms_conf.ibms.log.monitor_loglevel , p_env->ibms_conf.ibms.log.monitor_output );
				IBPCleanLogEnv();
				IBPInitLogEnv( p_env->ibms_conf.ibms.log.iblog_server , "ibms.monitor" , p_env->ibms_conf.ibms.log.event_output , IBPConvertLogLevel(ibms_conf.ibms.log.monitor_loglevel) , "%s" , p_env->ibms_conf.ibms.log.monitor_output );
				INFOLOGSG( "InitLogEnv iblog_server[%s] event_output[%s] monitor_output[%s][%s]" , p_env->ibms_conf.ibms.log.iblog_server , p_env->ibms_conf.ibms.log.event_output , p_env->ibms_conf.ibms.log.monitor_loglevel , p_env->ibms_conf.ibms.log.monitor_output );
				
				goto _GOTO_WAITPID;
			}
			
			ERRORLOGSG( "fork failed , errno[%d]" , errno );
			return -1;
		}
		
		if( WEXITSTATUS(status) == 0 && WIFSIGNALED(status) == 0 && WTERMSIG(status) == 0 )
		{
			INFOLOGSG( "waitpid[%d] WEXITSTATUS[%d] WIFSIGNALED[%d] WTERMSIG[%d]" , pid , WEXITSTATUS(status) , WIFSIGNALED(status) , WTERMSIG(status) );
		}
		else
		{
			ERRORLOGSG( "waitpid[%d] WEXITSTATUS[%d] WIFSIGNALED[%d] WTERMSIG[%d]" , pid , WEXITSTATUS(status) , WIFSIGNALED(status) , WTERMSIG(status) );
		}
		
		close( p_env->pipe_session.pipe_fds[1] );
		
		sleep(1);
	}
	
	return 0;
}

int _monitor( void *pv )
{
	struct IbmsEnv	*p_env = (struct IbmsEnv *)pv ;
	
	int		nret = 0 ;
	
	IBPCleanLogEnv();
	IBPInitLogEnv( p_env->ibms_conf.ibms.log.iblog_server , "ibms.monitor" , p_env->ibms_conf.ibms.log.event_output , IBPConvertLogLevel(p_env->ibms_conf.ibms.log.monitor_loglevel) , "%s" , p_env->ibms_conf.ibms.log.monitor_output );
	
	INFOLOGSG( "--- ibms.monitor begin --- " );
	
	nret = monitor( p_env ) ;
	
	INFOLOGSG( "--- ibms.monitor end --- " );
	
	CleanEnvironment( p_env );
	exit(0);
}

